02 Vasking av data

Vi importerer et offentlig datasett og ser på vanlige vaskemidler


In [140]:
import pandas as pd

Vi bruker her oversikten over lusetellinger fra fiskehelse.no/ Mattilsynet igjen


In [141]:
df = pd.read_excel('data/fiskehelse_2017-10-27-lakselus_per_fisk.xlsx')

Fikk vi med alle rader og kolonner?

Ta en kikk i Excel-filen din og se etter antall rader og antall kolonner og sammenlikn med tallet du med bruk av df.shape.


In [142]:
df.shape


Out[142]:
(61757, 16)

Det første tallet er rader, det andre er kolonner. Vi har altså over 61.757 rader. Og det stemmer med rader i Excel-filen. Så langt alt fint!

Ta en sjekk for å se at dataene ser ok ut

Vi sjekker topp og bunn


In [143]:
df.head(n=3)


Out[143]:
Uke År Lokalitetsnummer Lokalitetsnavn Voksne hunnlus Lus i bevegelige stadier Fastsittende lus Brakklagt Kommune Fylkesnummer Fylke Lat Lon Lusegrense uke Over lusegrense uke Sjøtemperatur
0 42 2017 15196 AGA Ø 0.00 0.58 0.10 Nei BØMLO 12.0 Hordaland 59.845100 5.261367 0.5 Nei 13.1
1 42 2017 12067 ALDALEN 0.19 0.33 0.00 Nei OS I HORDALAND 12.0 Hordaland 60.249950 5.571917 0.5 Nei 10.0
2 42 2017 12982 ALDEØYNA 0.45 2.25 0.12 Nei ASKVOLL 14.0 Sogn og Fjordane 61.310249 4.769050 0.5 Nei 13.2

In [144]:
df.tail(n=3)


Out[144]:
Uke År Lokalitetsnummer Lokalitetsnavn Voksne hunnlus Lus i bevegelige stadier Fastsittende lus Brakklagt Kommune Fylkesnummer Fylke Lat Lon Lusegrense uke Over lusegrense uke Sjøtemperatur
61754 1 2017 37857 NaN NaN NaN NaN Ja NaN NaN NaN NaN NaN Ukjent Ukjent NaN
61755 1 2017 37937 NaN NaN NaN NaN Ja NaN NaN NaN NaN NaN Ukjent Ukjent NaN
61756 1 2017 37877 NaN NaN NaN NaN Ja NaN NaN NaN NaN NaN Ukjent Ukjent NaN

Hvilke kolonner har vi og hva slags datatype har de?


In [145]:
df.dtypes


Out[145]:
Uke                           int64
År                            int64
Lokalitetsnummer              int64
Lokalitetsnavn               object
Voksne hunnlus              float64
Lus i bevegelige stadier    float64
Fastsittende lus            float64
Brakklagt                    object
Kommune                      object
Fylkesnummer                float64
Fylke                        object
Lat                         float64
Lon                         float64
Lusegrense uke               object
Over lusegrense uke          object
Sjøtemperatur               float64
dtype: object

Forklaring: int64 betyr heltall, object betyr som regel at det er tekst, float64 betyr et tall med desimaler.

Fjern kolonner du ikke trenger

Gjør det det mer oversiktlig å jobbe med. Her kan vi fjerne lat og lon kolonnene som angir kartreferanse.


In [146]:
df = df.drop(['Lat', 'Lon'], axis='columns')

Forklaring: Her lager vi en ny DataFrame med samme navnet, der vi dropper kolonnene Lat og Lon. axis=columns betyr at det er kolonner vi skal droppe, ikke rader.

Endre kolonnenavn

Noen ganger har kolonnene rare og lange navn, la oss lage dem kortere. Vi lager et objekt som viser hvilke kolonner vi vil endre navn på og til hva.


In [147]:
df = df.rename(columns={'Voksne hunnlus': 'hunnlus', 'Sjøtemperatur': 'sjotemp'})

Har vi manglende data?

Har vi rader uten data, eller kolonner uten data?

La oss først se på de 5 første radene.


In [148]:
df.head(n=5)


Out[148]:
Uke År Lokalitetsnummer Lokalitetsnavn hunnlus Lus i bevegelige stadier Fastsittende lus Brakklagt Kommune Fylkesnummer Fylke Lusegrense uke Over lusegrense uke sjotemp
0 42 2017 15196 AGA Ø 0.00 0.58 0.10 Nei BØMLO 12.0 Hordaland 0.5 Nei 13.1
1 42 2017 12067 ALDALEN 0.19 0.33 0.00 Nei OS I HORDALAND 12.0 Hordaland 0.5 Nei 10.0
2 42 2017 12982 ALDEØYNA 0.45 2.25 0.12 Nei ASKVOLL 14.0 Sogn og Fjordane 0.5 Nei 13.2
3 42 2017 11756 ALLERSHOLMEN NaN NaN NaN Ja AUSTRHEIM 12.0 Hordaland 0.5 NaN NaN
4 42 2017 13271 ALMURDEN NaN NaN NaN Ja FLATANGER 17.0 Nord-Trøndelag 0.5 NaN NaN

Allerede her ser vi gjengangeren NaN som betyr Not a Number. Altså at denne cellen ikke har en numerisk verdi (slik som de andre i kolonnen)

La oss se hvor mange rader som mangler verdi (isnull) i hunnlus-feltet


In [149]:
df['hunnlus'].isnull().sum()


Out[149]:
39567

Oi, nokså mange uten verdi. Trolig har ikke de rapportert lusetall den uka. Vi skal se på det senere.

Fyll inn manglende data

Vi ser på et nytt eksempel, en Excel-fil der det er manglende data i mange celler.


In [150]:
df2 = pd.read_excel('data/bord4_20171028_kommunedummy.xlsx')
df2


Out[150]:
Fylke Kommune Verdi
0 Hordaland Bergen 100
1 NaN Askøy 234
2 NaN Fjell 53
3 NaN Sund 4
4 Rogaland Stavanger 34
5 NaN Sandnes 343
6 NaN Sauda 54
7 NaN Haugesund 34
8 Sogn og Fjordane Førde 43
9 NaN Florø 23
10 NaN Jølster 12
11 NaN Stryn 34

Her ser vi et typisk mønster der kun første raden i hvert fylke har verdi i fylkekolonnen. For å kunne behandle disse dataene i Pandas må alle ha verdi. Så la oss fylle celler med tomme verdier (fillna) nedover, en såkalt Forward Fill eller ffill


In [151]:
df2['Fylke'] = df2['Fylke'].fillna(method='ffill')
df2


Out[151]:
Fylke Kommune Verdi
0 Hordaland Bergen 100
1 Hordaland Askøy 234
2 Hordaland Fjell 53
3 Hordaland Sund 4
4 Rogaland Stavanger 34
5 Rogaland Sandnes 343
6 Rogaland Sauda 54
7 Rogaland Haugesund 34
8 Sogn og Fjordane Førde 43
9 Sogn og Fjordane Florø 23
10 Sogn og Fjordane Jølster 12
11 Sogn og Fjordane Stryn 34

Normaliser dataene

Er det mennesker som har punchet dataene du har? Da er det garantert ord som er skrevet NESTEN likt og som roter til data-analysen din.

Vi bruker her et datasett fra UiBs medborgerpanel hvor velgernes holdninger til andre partier er angitt. Datasettet er satt sammen av flere Excel-filer, laget på ulikt tidspunkt.

La oss se på dataene


In [152]:
df = pd.read_csv('data/uib_medborgerpanelet_20170601_partiomparti.csv')
df.head()


Out[152]:
runde_nr parti_valgt_2013 omtaler_parti kategori andel konfidensintervall_fra konfidensintervall_til N
0 1 FRP KRF Misliker 0.513462 0.4703669 0.5563569 520
1 1 FRP KRF Nøytral 0.259615 0.223626 0.2991649 520
2 1 FRP KRF Liker 0.226923 0.1928411 0.2650506 520
3 2 FRP KRF Misliker 0.606061 0.5545943 0.6552765 363
4 2 FRP KRF Nøytral 0.170799 0.135331 0.2132696 363

Det er ofte lurt å se hva slags unike verdier som finnes i en kolonne. Det kan du gjøre slik.


In [153]:
df['omtaler_parti'].value_counts().to_frame().sort_index()


Out[153]:
omtaler_parti
AP 192
Ap 24
FRP 192
FrP 24
H 48
Høyre 168
KRF 192
KrF 24
MDG 216
SP 192
SV 216
Sp 24
V 48
Venstre 168

Her var det mye forskjellig! Legg merke til at partiene er skrevet på forskjellige måter. Det betyr trøbbel om vi skal gruppere senere.

Vi må normalisere disse verdiene, dvs samle oss om en måte å skrive på partiene på. En måte å gjøre det på er å lage en fra-til liste med verdier.


In [154]:
partimapping = {
    'FRP': 'Frp',
    'FrP': 'Frp',
    'AP': 'Ap',
    'Høyre': 'H',
    'SP': 'Sp',
    'Venstre': 'V',
    'KRF': 'KrF'  
}

Så må vi fortelle Pandas at vi vil bytte ut innholdet i de tre kolonnene som inneholder partinavn med den riktige formen av partinavn.


In [155]:
df = df.replace({
    'parti_valgt_2013': partimapping, 
    'omtaler_parti': partimapping}
)

Så tar vi igjen en sjekk på hvilke unike verdier vi har


In [156]:
df['omtaler_parti'].value_counts().to_frame().sort_index()


Out[156]:
omtaler_parti
Ap 216
Frp 216
H 216
KrF 216
MDG 216
SV 216
Sp 216
V 216

Se der ja! Mye bedre. Kun en måte å skrive hvert parti på. Nå kan vi gå i gang med gruppering, pivotering og andre fancy ting